package cpr;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.Reader;
import java.io.Writer;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.SortedSet;
import java.util.TreeSet;

import cpr.data.AR;
import cpr.data.AREntry;
import cpr.data.HLIterator;
import cpr.data.HLVector;
import cpr.data.RuleComparable;


public class Utils {
	public static int returns = 0;

	public static List readRulesFromFile( String filename, int maxRecord ) {
        try {
            Reader f = new FileReader(filename);
            BufferedReader br = new BufferedReader(f);
            String s = null;
            int currentRecord = 0;

            List rules = new ArrayList();
            do {
                s=br.readLine();
                if (s!=null) {
                    Rule rule = Rule.createFromString(s);
                    rules.add(rule);
                    currentRecord ++;
                }
                if (maxRecord>0) {
                    if (currentRecord>=maxRecord) s = null;
                }                    
                
            }while (s!=null);
            f.close();            
            
            
            return rules;

            
        } catch (Exception ex) {
            ex.printStackTrace();
        }
        return null;
	}

    static int findRule(int ruleNr, List list) {
        for (int i=0;i<list.size();i++) {
            Rule rule = (Rule) list.get(i);
            if (rule.ruleNr==ruleNr) return i;
        }
        throw new RuntimeException("Rule "+ruleNr+" not found!");
    }
     
    public static void saveEntriesMap(String filename, List arl, List rules) {
        throw new RuntimeException();
    }
    public static List loadEntriesMap(String filename, List rules) {
        throw new RuntimeException();
//        List arl = new ArrayList();
//        HLSerializer ser = new HLSerializer(rules);
//        try {
//            Reader f = new FileReader(filename);
//            BufferedReader br = new BufferedReader(f);
//            AR ar = null;
//            do {
//                ar = ser.fromStringAR(br);
//                if (ar!=null) {
//                    arl.add(ar);
//                }
//            }while (ar!=null);
//            f.close();
//            return arl;
//        } catch (Exception ex){
//            ex.printStackTrace();
//        }
//        return null;
    }

   
   public static void copyRulesFromHLFile(String filename, int maxRecord) {
        try {
            Reader f = new FileReader(filename);
            Writer wr = new FileWriter(filename+maxRecord);
            BufferedReader br = new BufferedReader(f);
            String s = null;
            int currentRecord = 0;
            
            do {
                s=br.readLine();
                if (s!=null) {
                    wr.write(s+"\n");
                    currentRecord ++;
                }
                if (maxRecord>0) {
                    if (currentRecord>=maxRecord) s = null;
                }
            }while (s!=null);
            f.close();            
            wr.close();            
            
        } catch (Exception ex) {
            ex.printStackTrace();
        }
        
    }
    
    public static void fileCopy(String readFrom, String writeTo) {
    	 try {
    	    	Reader f = new FileReader(readFrom);
		        BufferedReader br = new BufferedReader(f);
		        Writer w = new FileWriter(writeTo);
		        BufferedWriter bw = new BufferedWriter(w);
		        String s = null;
		        do {
		            s=br.readLine();
		            if (s!=null) {
		            	bw.write(s.trim()+"\n");
		            }
		        }while (s!=null);
		        f.close();  
		        bw.close();
	    } catch (Exception ex) {
	        ex.printStackTrace();
	    }
    }
    

    
    static class SplitCluster {
    	private Rule aRule;
    	private int aCounter;
    	private HLVector aVector;
    	private String accordingToRule;
    	SplitCluster(Rule rule, HLVector vector) {
    		aRule = rule;
    		aCounter = 0;
    		aVector = vector;
    	}
    	public int getCounter() {
    		return aCounter;
    	}
    	public String getAccordingToRule() {
    		if (accordingToRule==null) {
    			accordingToRule = printRuleAccordingToVectorOld(aRule, aVector);
    		}
    		return accordingToRule;
    	}
    }
    
//    public static Map printRulesFromHLFile(String filename, HLVector vector, int RULES_TO_LOAD) {
//        try {
//        	Printer.print("score="+vector.score+"="+ScoreHelper.printHLVectorAsArray(vector)+"\n");
//            Reader f = new FileReader(filename);
//            BufferedReader br = new BufferedReader(f);
//            String s = null;
//            int cnt = 1;
//            Map set = new HashMap();
//            int ruleNr = 0;
//            int ruleNrGlobal = 0;
//           
//            do {
//                s=br.readLine();
//                if (s!=null) {
//                    Rule r = Rule.createFromHLString(s,ruleNr, ruleNrGlobal);
//                    ruleNr++;
//                    ruleNrGlobal++;
//                    
//                    int oldSize = set.size();
//                    String si = printRuleAccordingToVectorOld(r, vector);
//                    SplitCluster c = (SplitCluster)set.get(si);
//                    //Integer c = (Integer)set.get(si);
//                    if (c==null) {
//                        c = new SplitCluster(r,vector);
//                    }
//                    c.aCounter++;
//                    set.put(si, c);
//                    
//                }
//                cnt++;
//                if ((RULES_TO_LOAD>0)&&(cnt>RULES_TO_LOAD)) {
//                    s = null;
//                }
//            }while (s!=null);
//            f.close();            
//
//
//            return set;
//            
//            
//        } catch (Exception ex) {
//            ex.printStackTrace();
//        }
//        return null;
//    }
//    
//    
//	public static List readRulesFromCPRFile(String filename, int maxRecord) {
//        try {
//            Reader f = new FileReader(filename);
//            BufferedReader br = new BufferedReader(f);
//            String s = null;
//            int currentRecord = 0;
//            
//            List rules = new ArrayList();
//            do {
//                s=br.readLine();
//                if (s!=null) {
//                    Rule rule = Rule.createFromCPRString(s);
//                    rules.add(rule);
//                    currentRecord ++;
//                }
//                if (maxRecord>0) {
//                    if (currentRecord>=maxRecord) s = null;
//                }
//            }while (s!=null);
//            f.close();            
//            
//            
//            return rules;
//
//            
//        } catch (Exception ex) {
//            ex.printStackTrace();
//        }
//        return null;
//	}
    
    
    
    public static String sec(long start, long end) {
        return ""+((end-start)/1);
    }
    
    
    public static long clusterCounter = 0;
    
    public static int compare(Rule aRuleOne, Rule aRuleTwo, HLVector aVectorOne, HLVector aVectionTwo) {
    	if (aVectorOne.score!=aVectionTwo.score) {
    		return aVectorOne.score-aVectionTwo.score;
    	} else {
    		return compare(aRuleOne, aRuleTwo, aVectorOne);
    	}
    }
    public static int compare(Rule aRuleOne, Rule aRuleTwo, HLVector vector) {
	   	 for (int h = 0; h < Rule.HLIS.length; h++) {
	         int hlIndex = Rule.HLH[h][vector.getValue(h)];
	         if((aRuleOne.getHLValueDigital(hlIndex)-aRuleTwo.getHLValueDigital(hlIndex))!=0){
	        	 return aRuleOne.getHLValueDigital(hlIndex)-aRuleTwo.getHLValueDigital(hlIndex);
	         }
	     }
   	return 0;
   }
    
    
    public static RuleComparable comparable(Rule aRule, HLVector aVector) {
    	return new RuleComparable(aRule, aVector);
    }
    public static boolean equals(Rule aRuleOne, Rule aRuleTwo, HLVector vector) {
	   	 
    	return compare(aRuleOne,  aRuleTwo,  vector)==0;
    }
    public static boolean equals(Rule aRuleOne, Rule aRuleTwo, HLVector aVectorOne, HLVector aVectorTwo) {
    	return compare(aRuleOne,  aRuleTwo,  aVectorOne, aVectorTwo)==0;
    }
    public static int hashCodeForProjection(Rule aRule, HLVector vector) {
  		return hashStringForProjectionDigital(aRule, vector);
    }
    public static int[] ruleValueFor(Rule aRule, HLVector vector) {
    	int[] result = new int[5];
    	 for (int h = 0; h < Rule.HLIS.length; h++) {
             int hlIndex = Rule.HLH[h][vector.getValue(h)];
             result[h] = aRule.getHLValueDigital(hlIndex);
         }
    	 return result;
    }

    public static int hashStringForProjectionDigital(Rule aRule, HLVector vector) {
    	RuleComparable rc = new RuleComparable(aRule, vector);
    	return rc.hashCode();
    }
    
    public static class HLReducedIterator implements Iterator {
        int[] HL_SCORE = new int[Rule.HL_SIZE];


        private int currScore;
        private final int maxScore = Rule.HL_SCORE[Rule.HL_DUCPR_PRODM]*2;
        private HLVector nextValue;
        private void computeNextValue() {
            nextValue = null;
            while ((currScore<maxScore)&&(nextValue==null)) {
                int[] decay =decayScore(currScore, HL_SCORE);
                if (decay!=null) {
                    nextValue = new HLVector(decay);
                }
                currScore++;
            }
        }
        public HLReducedIterator(int start) {
            HL_SCORE[Rule.HL_SOLD_TO_ROOT]       = 0;
            HL_SCORE[Rule.HL_SOLD_TO_REGION]     = 4;
            HL_SCORE[Rule.HL_SOLD_TO_SUBREG]     = 128;
            HL_SCORE[Rule.HL_SOLD_TO_COUNTRY]    = 8192;
            HL_SCORE[Rule.HL_SOLD_TO_CUSTOMER]   = 1048576;
            HL_SCORE[Rule.HL_DUCPR_ROOT]         = 0;
            HL_SCORE[Rule.HL_DUCPR_PRODH1]       = 32;
            HL_SCORE[Rule.HL_DUCPR_PRODH2]       = 1024;
            HL_SCORE[Rule.HL_DUCPR_PRODH3]       = 32768;
            HL_SCORE[Rule.HL_DUCPR_PRODH4]       = 131072;
            HL_SCORE[Rule.HL_DUCPR_PRODG]        = 262144;
            HL_SCORE[Rule.HL_DUCPR_PRODM]        = 4194304;
        	
            currScore = start;
            computeNextValue();
        }
        public boolean hasNext() {
            return (nextValue!=null);
        }

        public Object next() {
            HLVector res = nextValue;
            computeNextValue();
            return res;
        }

        public void remove() {
        }
        
    }

//    public static int computeAllPossibleScoreNumbers() {
//        int currScore = 0;
//        int maxScore = Rule.HL_SCORE[Rule.HL_SHIP_TO_CUSTOMER]*2;
//        int counter = 0;
//        while (currScore<maxScore) {
//            int[] decay =decayScore(currScore);
//            if (decay!=null) {
//                counter++;
//            }
//            currScore++;
//        }
//        return counter;
//    }
    
    public static int findScoreInHL_SCORE(int score, int[] a_hl_score) {
        for(int i=0;i<Rule.HL_SCORE.length;i++) {
            if (a_hl_score[i]==score) return i;
        }
        return -1;
    }
    
    public static int[] findIndexInHLH(int index) {
        for (int h=0;h<Rule.HLIS.length;h++) {
            for (int i =0;i<Rule.HLH[Rule.HLIS[h]].length;i++) {
                if (index==Rule.HLH[Rule.HLIS[h]][i]) return new int[]{h,i};
            }
        }
        return null;
    }
    public static Iterator getHLVectorIterator() {
        return new HLIterator(0);
    }
    public static Iterator getHLVectorIterator(int start) {
        return new HLIterator(start);
    }
    public static Iterator getHLReducedVectorIterator(int start) {
        return new HLReducedIterator(start);
    }    
    
    public static List getHLVectorList(Iterator it) {
        List list=  new LinkedList();
        while (it.hasNext()) {
            HLVector vec = (HLVector) it.next();
            list.add(vec);
        }
        return list;
    }
    
    public static void selectBestGroup(Collection rules, Collection resultRules, HLVector vector) {
//        Map<String,Integer> am = new HashMap<String,Integer>();
//        for (Iterator iter = rules.iterator(); iter.hasNext();) {
//            Rule r = iter.next();
//            if (am.get(r.attrValue)==null) {
//                am.put(r.attrValue,new Integer(1));
//            } else {
//                Integer it = am.get(r.attrValue);
//                am.put(r.attrValue, new Integer(it.intValue()+1));
//            }
//        }
//        
//        int min = -1;
//        for (Iterator<Map.Entry<String,Integer>> iter = am.entrySet().iterator(); iter.hasNext();) {
//            Map.Entry<String,Integer> entry = iter.next();
//            if (min==-1) {
//                min = entry.getValue().intValue()+1;
//            }
//            if (min>entry.getValue().intValue()) {
//                min = entry.getValue().intValue();
//            }
//        }
//        for (Iterator iter = rules.iterator(); iter.hasNext();) {
//            Rule r = iter.next();
//            int count = am.get(r.attrValue).intValue();
//            if (count==min) {
//                resultRules.add(r);
//                return;
//            }
//        }
//        
//        resultRules.add(rules.iterator().next());
        for (Iterator iter = rules.iterator(); iter.hasNext();) {
            Rule element = (Rule) iter.next();
            if (element.getOtherAttr(1)>0) {
                resultRules.add(element);
            }
            
        }
//        resultRules.addAll(rules);
    }
    
//    public static void decayRules(Collection rules) {
//        List workRules = new ArrayList(rules.size());
//        List tmpRules = new ArrayList(4);
//        List todelRules = new ArrayList(4);
//        HLVector tmpVector = new HLVector(null,0);
//        workRules.addAll(rules);
//        while (workRules.size()>0) {
//            tmpRules.clear();
//            findBestGroupingOftheLowestScore(workRules,tmpRules, tmpVector, tmpVector.getScore());
//            todelRules.clear();
//            for (Iterator iter = tmpRules.iterator(); iter.hasNext();) {
//                Rule aMasterRule= iter.next();
//                Printer.println("Group=["+getScore(tmpVector)+"] "+printRuleAccordingToVector(aMasterRule, tmpVector)+ "="+ aMasterRule.attrValue);
//                int mh = hashCodeForProjection(aMasterRule, tmpVector);
//                for (Iterator iter2 = workRules.iterator(); iter2.hasNext();) {
//                    Rule aRule= iter2.next();
//                    int rh = hashCodeForProjection(aRule, tmpVector);
//                    if (mh==rh) {
//                        todelRules.add(aRule);
//                    }
//                }
//                
//            }
//            workRules.removeAll(todelRules);
//        }
//    }

    public static void cleanRules(Collection rules) {
        for (Iterator iter2 = rules.iterator(); iter2.hasNext();) {
            Rule aRule = (Rule) iter2.next();
            aRule.setOtherAttr(0, 0);
            aRule.setOtherAttr(2, 0);
        } 
    }
    public static boolean areThereUncoveredLines(Collection rules) {
    	boolean res = true;
        for (Iterator iter2 = rules.iterator(); iter2.hasNext();) {
            Rule aRule = (Rule) iter2.next();
            if (aRule.getOtherAttr(2)==1) {
            	res = false;
            	break;
            }
         }
        return res;
    }
    static SortedSet ss = new TreeSet(new Comparator () {

        public int compare(Object o1, Object o2) {
            Map.Entry e1 = (Map.Entry) o1;
            Map.Entry e2 = (Map.Entry) o2;
            AREntry a1 = (AREntry)e1.getValue();
            AREntry a2 = (AREntry)e2.getValue();
            HLVector v1 = a1.vector;
            HLVector v2 = a2.vector;
            int s1 = Utils.getScore(v1);
            int s2 = Utils.getScore(v2);
            return s1-s2;
        }
    });
        
    public static void computeARentriesList(AR aAR) {
    	
    	Set ares= aAR.entriesMap.entrySet();
    	ss.clear();
        ss.addAll(ares);
        
        aAR.entriesList = new LinkedList();
        for (Iterator iterator = ss.iterator(); iterator.hasNext();) {
			Map.Entry element = (Map.Entry) iterator.next();
            AREntry are =(AREntry)element.getValue();
			aAR.entriesList.add(are);
		}
        aAR.entriesMap=null;
    }
    
    static class HLRuleCounter {
        public final static String CODE_DUP = "DUP";
        Rule rule;
        int counter;
        String code;
    }
    
    public static void findBestGroupingOftheLowestScore(Collection rules, Collection resultRules, HLVector resultVector, int start ){
        List possible = new LinkedList();
        HLVector lastVector = null;
        for (Iterator iter = getHLVectorIterator(start); iter.hasNext();) {
            HLVector vector = (HLVector)iter.next();
            int vectorScore = getScore(vector);
            Map hcMap = new HashMap();
            if (!iter.hasNext()) {
                lastVector = vector;
            }
            for (Iterator ruleIt = rules.iterator(); ruleIt.hasNext();) {
                Rule aRule = (Rule)ruleIt.next();
                Integer rh = new Integer(hashCodeForProjection(aRule, vector));
//                if (aRule.getOtherAttr(0)==-1) {

                    if (hcMap.get(rh)!=null) {
                        HLRuleCounter counter = (HLRuleCounter)hcMap.get(rh);
                        
                        if (HLRuleCounter.CODE_DUP.equals( counter.code)) {
                            // already duplicated 
                        } else {
                            Rule tmpR = counter.rule;
                            if (tmpR.getOtherAttr(0)>vectorScore) {
                                // the rule is already coveded by another rule with a higher score
                                if (!aRule.attrValue.equals(tmpR.attrValue)) {
                                    counter.code = HLRuleCounter.CODE_DUP; 
                                } 
                            } else if (tmpR.getOtherAttr(0)>0) {
                                // the rule is already coveded by another rule with a lower score
                                if (!aRule.attrValue.equals(tmpR.attrValue)) {
                                    counter.code = HLRuleCounter.CODE_DUP; 
                                } else {
                                    counter.rule = aRule; 
                                }
                            } else {
                                // new rule
                                if (!aRule.attrValue.equals(tmpR.attrValue)) {
                                    counter.code = HLRuleCounter.CODE_DUP; 
                                } else {
                                    counter.counter++; 
                                }
                            }
                        }
                    } else {
                        HLRuleCounter counter = new HLRuleCounter();
                        counter.rule = aRule;
                        counter.counter = 1;
                        hcMap.put(rh,counter);
                    }
//                }
            }
            
            for (Iterator iterator = hcMap.entrySet().iterator(); iterator.hasNext();) {
                Map.Entry entry = (Map.Entry)iterator.next();
                HLRuleCounter counter = (HLRuleCounter)entry.getValue();
                if (!HLRuleCounter.CODE_DUP.equals(counter.code)) {
                    Rule aRule = counter.rule;
                    if (aRule.getOtherAttr(0)==-1) {
                        possible.add(aRule);
                        aRule.setOtherAttr(1, counter.counter);
                        if (counter.counter>1) {
                            counter.counter = counter.counter;
                        }
                    }
                }
                
            }
            

            
            if (possible.size()>0) {
                resultVector.copyFrom(vector);
                break;
            }
            
        }
        if (lastVector!=null) {
            resultVector.copyFrom(lastVector);
        }
        selectBestGroup(possible, resultRules, resultVector);
    }
    
    
    
    
    
    public static void findBestGroupingOfScore(Collection rules, Collection resultRules, HLVector resultVector, int score ){
        List possible = new LinkedList();
        Iterator iter = getHLVectorIterator(score);
        if (iter.hasNext()) {
            HLVector vector = (HLVector)iter.next();
            int vectorScore = getScore(vector);
            Map hcMap = new HashMap();
            for (Iterator ruleIt = rules.iterator(); ruleIt.hasNext();) {
                Rule aRule = (Rule)ruleIt.next();
                Integer rh = new Integer(hashCodeForProjection(aRule, vector));
//                Printer.println(hashCodeForProjection(aRule, vector)+ " "+hashStringForProjection(aRule, vector)+ " "+aRule.toString());
                
                
                
                /*
                 * 
                 * 1. map does not contain rh
                 *      -> crreate a new entry, 
                 *          counter.counter = 1
                 *          counter.attr0 = vectorScore
                 *          counter.rule = aRule
                 * 2. map does contain rh
                 *    2.1. already duplicated
                 *    -> return
                 *    
                 *    not yet duplicated
                 *    2.2. inspecting rule has score>vectorScore
                 *    -> we dont care
                 * 
                 */
                
                
                
                if (hcMap.get(rh)!=null) {
                    HLRuleCounter counter = (HLRuleCounter)hcMap.get(rh);
                    
                    if (HLRuleCounter.CODE_DUP.equals( counter.code)) {
                        // already duplicated
                    } if (aRule.getOtherAttr(0)>vectorScore) {
                    } else {
                        Rule tmpR = counter.rule;
                        if (tmpR.getOtherAttr(0)<vectorScore) {
                            // the rule is already coveded by another rule with a lower score
                            if (!aRule.attrValue.equals(tmpR.attrValue)) {
                                counter.code = HLRuleCounter.CODE_DUP; 
                            } else {
                                if (aRule.getOtherAttr(2)!=1) {
                                    counter.rule = aRule;
                                    aRule.setOtherAttr(0, vectorScore);
                                }
                                counter.counter++; 
                            }
                        } else {
                            // the rule is not covered by another rule with a lower score
                            
                            if (!aRule.attrValue.equals(tmpR.attrValue)) {
                                counter.code = HLRuleCounter.CODE_DUP; 
                            } else {
                                if (aRule.getOtherAttr(2)!=1) {
                                    counter.rule = aRule;
                                    aRule.setOtherAttr(0, vectorScore);
                                }
                                counter.counter++; 
                            }
                        }
                    }
                } else {
                    HLRuleCounter counter = new HLRuleCounter();
                    counter.rule = aRule;
                    aRule.setOtherAttr(0, vectorScore);
                    counter.counter = 1;
                    hcMap.put(rh,counter);
                }
            }
            
            for (Iterator iterator = hcMap.entrySet().iterator(); iterator.hasNext();) {
                Map.Entry entry = (Map.Entry)iterator.next();
                HLRuleCounter counter = (HLRuleCounter)entry.getValue();
                if (!HLRuleCounter.CODE_DUP.equals(counter.code)) {
                    Rule aRule = counter.rule;
                    if (aRule.getOtherAttr(0)==vectorScore) {
                        if (aRule.getOtherAttr(2)!=1) {
                            possible.add(aRule);
                            aRule.setOtherAttr(1, counter.counter);
                            if (counter.counter>1) {
                                counter.counter = counter.counter;
                            }
                        }
                    }
                }
                
            }
            

            
            if (possible.size()>0) {
                resultVector.copyFrom(vector);
            }
            
        }
        selectBestGroup(possible, resultRules, resultVector);
    }
    
    
    public static int getScore(int[] sc) {
        int score = 0;
        for (int h=0;h<Rule.HLIS.length;h++) {
            int hlIndex = Rule.HLH[h][sc[h]];
            score = score + Rule.HL_SCORE[hlIndex];
        }
        return score;
    }
    
    public static int getScore(HLVector vector) {
        int score = 0;
        for (int h=0;h<Rule.HLIS.length;h++) {
            int hlIndex = Rule.HLH[h][vector.getValue(h)];
            score = score + Rule.HL_SCORE[hlIndex];
        }
        return score;
    }
    

    
    public static String printRuleAccordingToVectorOld(Rule aRule, HLVector vector) {
        StringBuffer sb = new StringBuffer();
        for (int h=0;h<Rule.HLIS.length;h++) {
            int hlIndex = Rule.HLH[h][vector.getValue(h)];
            String v = aRule.getHLValue(hlIndex);
            sb.append(v+" ");
        }
        return sb.toString();
    }
    

    
    public static int printRuleAccordingToVectorDigital(Rule aRule, HLVector vector) {
    	 return hashStringForProjectionDigital(aRule, vector);
    }

    public static int compareRuleAccordingToVectorLongFast(Rule aRule1, Rule aRule2, HLVector vector) {
        int i1=0;
        int i2=0;
        for (int i = 0; i < aRule1.HL_LEVEL.length; i++) {
            i1+=Rule.HL_LEVEL[i];
            i2+=Rule.HL_LEVEL[i];
        }
        return i1-i2;
    }

    public static int[] decayScore(int score, int[] a_hl_score) {
        int idx = 1;
        List indexes = new ArrayList();
        while (idx<=Rule.HL_SCORE[Rule.HL_DUCPR_PRODM]) {
            if ((score&idx)!=0) {
                int hl_index = findScoreInHL_SCORE(idx,a_hl_score);
                if (hl_index==-1) 
                	return null;
                indexes.add(new Integer(hl_index));
                if (indexes.size()>5) {
                    return null;
                }
            }
            idx = idx<<1;
        }
        
        int[] found = new int[5];
        for (int i=0;i<found.length;i++) {
            found[i]=-1;
        }
        for (int i=0;i<indexes.size();i++) {
            int ci = ((Integer)indexes.get(i)).intValue();
            int[] hi = findIndexInHLH(ci);
            if (found[hi[0]]!=-1) {
                return null;
            }
            found[hi[0]] = hi[1];
        }
        for (int i=0;i<found.length;i++) {
            if (found[i]==-1) {
                found[i] = 0;
            }
        }
        return found;
    }
    
    
    
    public static Collection selectRuleScores(Collection rules) { //, String attrName, String attrValue
        Set r = new HashSet();
        for (Iterator iter = rules.iterator(); iter.hasNext();) {
            Rule aRule = (Rule) iter.next();
                r.add(aRule.score);
        }
        return r;    
    }

    public static Collection selectRules(Collection rules, String score) { //, String attrName, String attrValue
        Set r = new HashSet();
        for (Iterator iter = rules.iterator(); iter.hasNext();) {
            Rule aRule = (Rule) iter.next();
            if (score.equals(aRule.score))
                r.add(aRule);
        }
        return r;    
    }
    
    
    public static Collection selectRuleAttributes(Collection rules, String score) {
        Map r = new HashMap();
        for (Iterator iter = rules.iterator(); iter.hasNext();) {
            Rule aRule = (Rule) iter.next();
            if (
                    score.equals(aRule.score) 
            ) {
                r.put(aRule.attrName+" "+aRule.attrValue,  new String[] {aRule.attrName, aRule.attrValue});
            }
        }
        return r.values();    
    }
    

    public static int selectRulesCount(Collection rules, String attrName, String attrValue) {
        int c=  0;
        for (Iterator iter = rules.iterator(); iter.hasNext();) {
            Rule aRule = (Rule) iter.next();
            if (
                    attrName.equals(aRule.attrName) &&
                    attrValue.equals(aRule.attrValue)
            ) {
                c++;
            }
        }
        return c;    
    }
    
    
    public static Collection selectRuleWithScoreAndAttr(Collection rules, String score, String attrName, String attrValue,int[] myKEYS) {
        Map r = new HashMap();
        for (Iterator iter = rules.iterator(); iter.hasNext();) {
            Rule aRule = (Rule) iter.next();
            if (
                    score.equals(aRule.score)&&
                    attrName.equals(aRule.attrName)&&
                    attrValue.equals(aRule.attrValue)
            ) {
                StringBuffer keyhash = new StringBuffer();
                for (int i = 0; i < myKEYS.length; i++) {
                    keyhash.append(aRule.getKeyValue(myKEYS[i])+" ");
                }
                if (r.get(keyhash.toString())!=null) {
                    Printer.println("Duplicated rule: "+ aRule+ " and "+ r.get(keyhash.toString()));
                }
                r.put(keyhash.toString(),aRule);
            }
        }
        return r.values();
    }
    
    
   
   
    public static List selectRuleWithScoreAndAttr(Collection rules, String score, String attrValue) {
        List r = new ArrayList();
        for (Iterator iter = rules.iterator(); iter.hasNext();) {
            Rule aRule = (Rule) iter.next();
            if (
                    score.equals(aRule.score)&&
                    attrValue.equals(aRule.attrValue)
            ) {
                r.add(aRule);
            }
        }
        return r;
    }
    public static List selectRules(Collection rules, int keyId, Collection keyValues) {
    	List r = new ArrayList();
        for (Iterator iter = rules.iterator(); iter.hasNext();) {
			Rule aRule = (Rule) iter.next();
			
			boolean found = false;
			String key = aRule.getKeyValue(keyId);
			for (Iterator iterator = keyValues.iterator(); iterator.hasNext();) {
				String v = (String) iterator.next();
				if (v.equals(key)) {
					found = true;
					break;
				}
				
			}
					
			if (found) {
	            r.add(aRule);
            }
		}
        return r;    	
    }
}
